import {
  defaultState,
  firstRender,
  ids,
  raiseChangeEvents,
  render,
  rendered,
  setState,
  state,
  template,
} from "../../src/base/internal.js";
import { updateChildNodes } from "../../src/core/dom.js";
import { templateFrom } from "../../src/core/htmlLiterals.js";
import ReactiveElement from "../../src/core/ReactiveElement.js";

// Locale list from https://stackoverflow.com/questions/3191664/list-of-all-locales-and-their-short-codes/28357857#28357857
// This includes only locales with regions; it omits languages without regions.
/** @type {IndexedObject<string>} */
const locales = {
  "af-NA": "Afrikaans (Namibia)",
  "af-ZA": "Afrikaans (South Africa)",
  "ak-GH": "Akan (Ghana)",
  "sq-AL": "Albanian (Albania)",
  "am-ET": "Amharic (Ethiopia)",
  "ar-DZ": "Arabic (Algeria)",
  "ar-BH": "Arabic (Bahrain)",
  "ar-EG": "Arabic (Egypt)",
  "ar-IQ": "Arabic (Iraq)",
  "ar-JO": "Arabic (Jordan)",
  "ar-KW": "Arabic (Kuwait)",
  "ar-LB": "Arabic (Lebanon)",
  "ar-LY": "Arabic (Libya)",
  "ar-MA": "Arabic (Morocco)",
  "ar-OM": "Arabic (Oman)",
  "ar-QA": "Arabic (Qatar)",
  "ar-SA": "Arabic (Saudi Arabia)",
  "ar-SD": "Arabic (Sudan)",
  "ar-SY": "Arabic (Syria)",
  "ar-TN": "Arabic (Tunisia)",
  "ar-AE": "Arabic (United Arab Emirates)",
  "ar-YE": "Arabic (Yemen)",
  "hy-AM": "Armenian (Armenia)",
  "as-IN": "Assamese (India)",
  "asa-TZ": "Asu (Tanzania)",
  "az-Cyrl-AZ": "Azerbaijani (Cyrillic, Azerbaijan)",
  "az-Latn-AZ": "Azerbaijani (Latin, Azerbaijan)",
  "bm-ML": "Bambara (Mali)",
  "eu-ES": "Basque (Spain)",
  "be-BY": "Belarusian (Belarus)",
  "bem-ZM": "Bemba (Zambia)",
  "bez-TZ": "Bena (Tanzania)",
  "bn-BD": "Bengali (Bangladesh)",
  "bn-IN": "Bengali (India)",
  "bs-BA": "Bosnian (Bosnia and Herzegovina)",
  "bg-BG": "Bulgarian (Bulgaria)",
  "my-MM": "Burmese (Myanmar [Burma])",
  "ca-ES": "Catalan (Spain)",
  "tzm-Latn-MA": "Central Morocco Tamazight (Latin, Morocco)",
  "chr-US": "Cherokee (United States)",
  "cgg-UG": "Chiga (Uganda)",
  "zh-Hans-CN": "Chinese (Simplified Han, China)",
  "zh-Hans-HK": "Chinese (Simplified Han, Hong Kong SAR China)",
  "zh-Hans-MO": "Chinese (Simplified Han, Macau SAR China)",
  "zh-Hans-SG": "Chinese (Simplified Han, Singapore)",
  "zh-Hant-HK": "Chinese (Traditional Han, Hong Kong SAR China)",
  "zh-Hant-MO": "Chinese (Traditional Han, Macau SAR China)",
  "zh-Hant-TW": "Chinese (Traditional Han, Taiwan)",
  "kw-GB": "Cornish (United Kingdom)",
  "hr-HR": "Croatian (Croatia)",
  "cs-CZ": "Czech (Czech Republic)",
  "da-DK": "Danish (Denmark)",
  "nl-BE": "Dutch (Belgium)",
  "nl-NL": "Dutch (Netherlands)",
  "ebu-KE": "Embu (Kenya)",
  "en-AS": "English (American Samoa)",
  "en-AU": "English (Australia)",
  "en-BE": "English (Belgium)",
  "en-BZ": "English (Belize)",
  "en-BW": "English (Botswana)",
  "en-CA": "English (Canada)",
  "en-GU": "English (Guam)",
  "en-HK": "English (Hong Kong SAR China)",
  "en-IN": "English (India)",
  "en-IE": "English (Ireland)",
  "en-JM": "English (Jamaica)",
  "en-MT": "English (Malta)",
  "en-MH": "English (Marshall Islands)",
  "en-MU": "English (Mauritius)",
  "en-NA": "English (Namibia)",
  "en-NZ": "English (New Zealand)",
  "en-MP": "English (Northern Mariana Islands)",
  "en-PK": "English (Pakistan)",
  "en-PH": "English (Philippines)",
  "en-SG": "English (Singapore)",
  "en-ZA": "English (South Africa)",
  "en-TT": "English (Trinidad and Tobago)",
  "en-UM": "English (U.S. Minor Outlying Islands)",
  "en-VI": "English (U.S. Virgin Islands)",
  "en-GB": "English (United Kingdom)",
  "en-US": "English (United States)",
  "en-ZW": "English (Zimbabwe)",
  "et-EE": "Estonian (Estonia)",
  "ee-GH": "Ewe (Ghana)",
  "ee-TG": "Ewe (Togo)",
  "fo-FO": "Faroese (Faroe Islands)",
  "fil-PH": "Filipino (Philippines)",
  "fi-FI": "Finnish (Finland)",
  "fr-BE": "French (Belgium)",
  "fr-BJ": "French (Benin)",
  "fr-BF": "French (Burkina Faso)",
  "fr-BI": "French (Burundi)",
  "fr-CM": "French (Cameroon)",
  "fr-CA": "French (Canada)",
  "fr-CF": "French (Central African Republic)",
  "fr-TD": "French (Chad)",
  "fr-KM": "French (Comoros)",
  "fr-CG": "French (Congo - Brazzaville)",
  "fr-CD": "French (Congo - Kinshasa)",
  "fr-CI": "French (Côte d’Ivoire)",
  "fr-DJ": "French (Djibouti)",
  "fr-GQ": "French (Equatorial Guinea)",
  "fr-FR": "French (France)",
  "fr-GA": "French (Gabon)",
  "fr-GP": "French (Guadeloupe)",
  "fr-GN": "French (Guinea)",
  "fr-LU": "French (Luxembourg)",
  "fr-MG": "French (Madagascar)",
  "fr-ML": "French (Mali)",
  "fr-MQ": "French (Martinique)",
  "fr-MC": "French (Monaco)",
  "fr-NE": "French (Niger)",
  "fr-RW": "French (Rwanda)",
  "fr-RE": "French (Réunion)",
  "fr-BL": "French (Saint Barthélemy)",
  "fr-MF": "French (Saint Martin)",
  "fr-SN": "French (Senegal)",
  "fr-CH": "French (Switzerland)",
  "fr-TG": "French (Togo)",
  "ff-SN": "Fulah (Senegal)",
  "gl-ES": "Galician (Spain)",
  "lg-UG": "Ganda (Uganda)",
  "ka-GE": "Georgian (Georgia)",
  "de-AT": "German (Austria)",
  "de-BE": "German (Belgium)",
  "de-DE": "German (Germany)",
  "de-LI": "German (Liechtenstein)",
  "de-LU": "German (Luxembourg)",
  "de-CH": "German (Switzerland)",
  "el-CY": "Greek (Cyprus)",
  "el-GR": "Greek (Greece)",
  "gu-IN": "Gujarati (India)",
  "guz-KE": "Gusii (Kenya)",
  "ha-Latn-GH": "Hausa (Latin, Ghana)",
  "ha-Latn-NE": "Hausa (Latin, Niger)",
  "ha-Latn-NG": "Hausa (Latin, Nigeria)",
  "haw-US": "Hawaiian (United States)",
  "he-IL": "Hebrew (Israel)",
  "hi-IN": "Hindi (India)",
  "hu-HU": "Hungarian (Hungary)",
  "is-IS": "Icelandic (Iceland)",
  "ig-NG": "Igbo (Nigeria)",
  "id-ID": "Indonesian (Indonesia)",
  "ga-IE": "Irish (Ireland)",
  "it-IT": "Italian (Italy)",
  "it-CH": "Italian (Switzerland)",
  "ja-JP": "Japanese (Japan)",
  "kea-CV": "Kabuverdianu (Cape Verde)",
  "kab-DZ": "Kabyle (Algeria)",
  "kl-GL": "Kalaallisut (Greenland)",
  "kln-KE": "Kalenjin (Kenya)",
  "kam-KE": "Kamba (Kenya)",
  "kn-IN": "Kannada (India)",
  "kk-Cyrl-KZ": "Kazakh (Cyrillic, Kazakhstan)",
  "km-KH": "Khmer (Cambodia)",
  "ki-KE": "Kikuyu (Kenya)",
  "rw-RW": "Kinyarwanda (Rwanda)",
  "kok-IN": "Konkani (India)",
  "ko-KR": "Korean (South Korea)",
  "khq-ML": "Koyra Chiini (Mali)",
  "ses-ML": "Koyraboro Senni (Mali)",
  "lag-TZ": "Langi (Tanzania)",
  "lv-LV": "Latvian (Latvia)",
  "lt-LT": "Lithuanian (Lithuania)",
  "luo-KE": "Luo (Kenya)",
  "luy-KE": "Luyia (Kenya)",
  "mk-MK": "Macedonian (Macedonia)",
  "jmc-TZ": "Machame (Tanzania)",
  "kde-TZ": "Makonde (Tanzania)",
  "mg-MG": "Malagasy (Madagascar)",
  "ms-BN": "Malay (Brunei)",
  "ms-MY": "Malay (Malaysia)",
  "ml-IN": "Malayalam (India)",
  "mt-MT": "Maltese (Malta)",
  "gv-GB": "Manx (United Kingdom)",
  "mr-IN": "Marathi (India)",
  "mas-KE": "Masai (Kenya)",
  "mas-TZ": "Masai (Tanzania)",
  "mer-KE": "Meru (Kenya)",
  "mfe-MU": "Morisyen (Mauritius)",
  "naq-NA": "Nama (Namibia)",
  "ne-IN": "Nepali (India)",
  "ne-NP": "Nepali (Nepal)",
  "nd-ZW": "North Ndebele (Zimbabwe)",
  "nb-NO": "Norwegian Bokmål (Norway)",
  "nn-NO": "Norwegian Nynorsk (Norway)",
  "nyn-UG": "Nyankole (Uganda)",
  "or-IN": "Oriya (India)",
  "om-ET": "Oromo (Ethiopia)",
  "om-KE": "Oromo (Kenya)",
  "ps-AF": "Pashto (Afghanistan)",
  "fa-AF": "Persian (Afghanistan)",
  "fa-IR": "Persian (Iran)",
  "pl-PL": "Polish (Poland)",
  "pt-BR": "Portuguese (Brazil)",
  "pt-GW": "Portuguese (Guinea-Bissau)",
  "pt-MZ": "Portuguese (Mozambique)",
  "pt-PT": "Portuguese (Portugal)",
  "pa-Arab-PK": "Punjabi (Arabic, Pakistan)",
  "pa-Guru-IN": "Punjabi (Gurmukhi, India)",
  "ro-MD": "Romanian (Moldova)",
  "ro-RO": "Romanian (Romania)",
  "rm-CH": "Romansh (Switzerland)",
  "rof-TZ": "Rombo (Tanzania)",
  "ru-MD": "Russian (Moldova)",
  "ru-RU": "Russian (Russia)",
  "ru-UA": "Russian (Ukraine)",
  "rwk-TZ": "Rwa (Tanzania)",
  "saq-KE": "Samburu (Kenya)",
  "sg-CF": "Sango (Central African Republic)",
  "seh-MZ": "Sena (Mozambique)",
  "sr-Cyrl-BA": "Serbian (Cyrillic, Bosnia and Herzegovina)",
  "sr-Cyrl-ME": "Serbian (Cyrillic, Montenegro)",
  "sr-Cyrl-RS": "Serbian (Cyrillic, Serbia)",
  "sr-Latn-BA": "Serbian (Latin, Bosnia and Herzegovina)",
  "sr-Latn-ME": "Serbian (Latin, Montenegro)",
  "sr-Latn-RS": "Serbian (Latin, Serbia)",
  "sn-ZW": "Shona (Zimbabwe)",
  "ii-CN": "Sichuan Yi (China)",
  "si-LK": "Sinhala (Sri Lanka)",
  "sk-SK": "Slovak (Slovakia)",
  "sl-SI": "Slovenian (Slovenia)",
  "xog-UG": "Soga (Uganda)",
  "so-DJ": "Somali (Djibouti)",
  "so-ET": "Somali (Ethiopia)",
  "so-KE": "Somali (Kenya)",
  "so-SO": "Somali (Somalia)",
  "es-AR": "Spanish (Argentina)",
  "es-BO": "Spanish (Bolivia)",
  "es-CL": "Spanish (Chile)",
  "es-CO": "Spanish (Colombia)",
  "es-CR": "Spanish (Costa Rica)",
  "es-DO": "Spanish (Dominican Republic)",
  "es-EC": "Spanish (Ecuador)",
  "es-SV": "Spanish (El Salvador)",
  "es-GQ": "Spanish (Equatorial Guinea)",
  "es-GT": "Spanish (Guatemala)",
  "es-HN": "Spanish (Honduras)",
  "es-419": "Spanish (Latin America)",
  "es-MX": "Spanish (Mexico)",
  "es-NI": "Spanish (Nicaragua)",
  "es-PA": "Spanish (Panama)",
  "es-PY": "Spanish (Paraguay)",
  "es-PE": "Spanish (Peru)",
  "es-PR": "Spanish (Puerto Rico)",
  "es-ES": "Spanish (Spain)",
  "es-US": "Spanish (United States)",
  "es-UY": "Spanish (Uruguay)",
  "es-VE": "Spanish (Venezuela)",
  "sw-KE": "Swahili (Kenya)",
  "sw-TZ": "Swahili (Tanzania)",
  "sv-FI": "Swedish (Finland)",
  "sv-SE": "Swedish (Sweden)",
  "gsw-CH": "Swiss German (Switzerland)",
  "shi-Latn-MA": "Tachelhit (Latin, Morocco)",
  "shi-Tfng-MA": "Tachelhit (Tifinagh, Morocco)",
  "dav-KE": "Taita (Kenya)",
  "ta-IN": "Tamil (India)",
  "ta-LK": "Tamil (Sri Lanka)",
  "te-IN": "Telugu (India)",
  "teo-KE": "Teso (Kenya)",
  "teo-UG": "Teso (Uganda)",
  "th-TH": "Thai (Thailand)",
  "bo-CN": "Tibetan (China)",
  "bo-IN": "Tibetan (India)",
  "ti-ER": "Tigrinya (Eritrea)",
  "ti-ET": "Tigrinya (Ethiopia)",
  "to-TO": "Tonga (Tonga)",
  "tr-TR": "Turkish (Turkey)",
  "uk-UA": "Ukrainian (Ukraine)",
  "ur-IN": "Urdu (India)",
  "ur-PK": "Urdu (Pakistan)",
  "uz-Arab-AF": "Uzbek (Arabic, Afghanistan)",
  "uz-Cyrl-UZ": "Uzbek (Cyrillic, Uzbekistan)",
  "uz-Latn-UZ": "Uzbek (Latin, Uzbekistan)",
  "vi-VN": "Vietnamese (Vietnam)",
  "vun-TZ": "Vunjo (Tanzania)",
  "cy-GB": "Welsh (United Kingdom)",
  "yo-NG": "Yoruba (Nigeria)",
  "zu-ZA": "Zulu (South Africa)",
};

class LocaleSelector extends ReactiveElement {
  // @ts-ignore
  get [defaultState]() {
    return Object.assign(super[defaultState], {
      value: navigator.language,
    });
  }

  [render](/** @type {PlainObject} */ changed) {
    super[render](changed);

    if (this[firstRender]) {
      this[ids].select.addEventListener("change", () => {
        this[raiseChangeEvents] = true;
        this.value = /** @type {any} */ (this[ids].select).value;
        this[raiseChangeEvents] = false;
      });
    }

    if (changed.value) {
      const value = this[state].value;
      /** @type {HTMLSelectElement} */ (this[ids].select).value = value;
    }
  }

  [rendered](changed) {
    super[rendered](changed);
    if (changed.value && this[raiseChangeEvents]) {
      const event = new CustomEvent("change", {
        detail: {
          value: this[state].value,
        },
      });
      this.dispatchEvent(event);
    }
  }

  get [template]() {
    const result = templateFrom.html`
      <style>
        :host {
          display: inline-block;
        }
      </style>
      <select id="select"></select>
    `;
    // Create options for all locales.
    const localeOptions = Object.keys(locales).map((locale) => {
      const option = document.createElement("option");
      option.value = locale;
      option.disabled = !localeSupported(locale);
      option.textContent = locales[locale];
      return option;
    });
    const select = result.content.getElementById("select");
    if (select) {
      updateChildNodes(select, localeOptions);
    }
    return result;
  }

  get value() {
    return this[state].value;
  }
  set value(value) {
    this[setState]({ value });
  }
}

/**
 * Heuristic that returns true if the given locale is supported.
 *
 * @private
 * @param {string} locale
 */
function localeSupported(locale) {
  const language = locale.split("-")[0];
  if (language === "en") {
    // Assume all flavors of English are supported.
    return true;
  }
  // Try formatting a Tuesday date, and if we get the English result "Tue",
  // the browser probably doesn't support the locale, and used the default
  // locale instead.
  const date = new Date("10 March 2015"); // A Tuesday
  const formatter = new Intl.DateTimeFormat(locale, { weekday: "short" });
  const result = formatter.format(date);
  return result !== "Tue";
}

export default LocaleSelector;
customElements.define("locale-selector", LocaleSelector);
